<?php
require_once 'Zend/Controller/Plugin/Abstract.php';

/**
 * 左右树插件
 * 
 * Zend Framework 专用
 * 
 * @example
 * 
 * 推荐建立一个模型，再模型里定义 树结构的表，及左右节点字段，并提供调用接口
 * $treeModel = new GoodsCategoryModel();
    	
   $p1 = $this->_request->getParam('d');
   switch($p1)
   {
    case 'delete':
    	$treeModel->deleteTree($this->_request->getParam('id'));
    	break;
    		
    default:
    			 
    	if($this->_request->isPost())
    	{
    		$post = $this->_request->getPost();
    		$treeModel->addTree($post);
    	}
    	break;
   }
    	
    $this->view->tree = $treeModel->getTreeList();
 * 
 * @author 高强
 */
class Custom_Controller_Plugin_Tree extends Zend_Controller_Plugin_Abstract
{
	protected $_db;
	protected $_table;
	
	private $_left;
	private $_right;
	private $_pk;
	
	private $_treedata;
	private $_treeval;
	
	/**
	 * 初始化
	 * 
	 * @param String $table     表
	 * @param String $left      左节点
	 * @param String $right     右节点
	 * @param String $prefix    表前缀
	 * 
	 */
	public function __construct($table, $left, $right, $pk)
	{
		$this->_table = $table;
		$this->_left = $left;
		$this->_right = $right;
		$this->_pk = $pk;
		
		$this->_db = Zend_Registry::get('db');
	}
	
	/**
	 * 查询行记录
	 * 
	 * 仅返回一条一维数组的行记录
	 *
	 * @param int 查询表达式，默认查询不指定条件。
	 * @return array
	 */
	private function row($id)
	{
		$select = new Zend_Db_Select($this->_db);
		
		$select->from($this->_table)
			->where($this->_pk.' = ?', $id)
			->limit(1);
		
		$result = $this->_db->fetchRow($select);
		
		// 无记录
		if (empty($result))
		{
			return array();
		}
		
		return $result;
	}
	
	/**
	 * 获取树的平行数组
	 * 
	 * @param string $textfield
	 * @param integer $id
	 */
	private function _getTree($textfield, $id = null)
	{
		if(!empty($id))
		{
			$tree = $this->row($id);
			
			$left_node = $tree[$this->_left] - 1;
			$right_node = $tree[$this->_right] + 1;
			
			$select = new Zend_Db_Select($this->_db);
			$select->from($this->_table)
				->where($this->_left . '> ?', $left_node)
				->where($this->_right . '< ?', $right_node)
				->order($this->_left.' ASC');
		}
		else
		{
			$select = new Zend_Db_Select($this->_db);
			$select->from($this->_table)
				->order($this->_left.' ASC');
		}
		
		return $this->_db->fetchAll($select);
	}
	
	/**
	 * 对获取的数组根据左右树算法创建JSON树结构
	 * 
	 * @param array $data
	 * @param string $textfield
	 * 
	 * @return array
	 */
	private function _getTreeNode($data, $textfield)
	{
		$node = array();
		
		if (0 == (($data[$this->_right] - $data[$this->_left] - 1) / 2))
		{
			if (empty($this->_treeval))
			{
				$data['text'] = $data[$textfield];
				
				return $data;
			}
			
			if (@!in_array($data[$this->_pk], $this->_treeval))
			{
				$node['id'] = $data[$this->_pk];
				$node['text'] = $data[$textfield];
				$node['checked'] = true;
				
				$this->_treeval[] = $data[$this->_pk];
			}
		}
		else
		{
			$node['id'] = $data[$this->_pk];
			$node['text'] = $data[$textfield];
		
			$this->_treeval[] = $data[$this->_pk];
			foreach ($this->_treedata as $val)
			{
				if ($val[$this->_left] > $data[$this->_left] && $val[$this->_right] < $data[$this->_right])
				{
					if (!in_array($val[$this->_pk], $this->_treeval))
					{
						$node['children'][] = $this->_getTreeNode($val, $textfield);
					}
				}
			}
		}
		
		return $node;
	}
	
	/**
	 * 获取JSON树形结构的开放接口
	 * 
	 * @param string $textfield
	 * @param integer $id
	 * @return array
	 */
	public function getTreeArray($textfield, $id = null)
	{
		$this->_treedata = $this->_getTree($textfield, $id);
		
		if (empty($this->_treedata))
		{
			return array();
		}
		
		return $this->_getTreeNode($this->_treedata[0], $textfield);
	}
	
	/**
	 * 树列表
	 * 
	 * 树状采用 “|-”方式输出
	 * 
	 * @param string 作为显示字段的字段名称
	 * @param integer 树干的ID，默认为树根。
	 * @return array
	 */
	public function getTreeList($textField, $id = null)
	{
		$tree = $this->_getTree($textField, $id);
		// 生成树
		$right = array();
		$tree_total = count($tree);
		
		for ($i = 0; $i < $tree_total; $i++)
		{
			if (count($right) > 0)
			{
				while ( $right[count($right) - 1] < $tree[$i][$this->_right] )
				{
					array_pop($right);
				}
			}
			
			$tree[$i]['tree'] = str_repeat('    ', count($right)) . '├';
			$tree[$i]['treeText'] = str_repeat('    ', count($right)) . '├' . $tree[$i][$textField];
			$right[] = $tree[$i][$this->_right];
		}
		
		return $tree;
	}
	
	/**
	 * 新增树
	 * 
	 * @param integer 父节点
	 * @param array 健值关联数组
	 * @return bool
	 */
	public function addTree($id, array $data = array())
	{
		if (empty($id) || empty($data))
		{
			return false;
		}
		
		// 父右节点
		$select = new Zend_Db_Select($this->_db);
		$select->from($this->_table)
			->where($this->_pk.' =?', $id);
		
		$row = $this->_db->fetchRow($select);
		$right_node = $row[$this->_right];

		// 添加步骤，移动左节点
		$sql = $this->_db->quoteInto(
			'UPDATE '.$this->_table.' SET '.$this->_left.' = '.$this->_left.' + 2 WHERE '.$this->_left. ' > ?', 
			$right_node - 1
		);
		$this->_db->query($sql);
		
		// 添加步骤， 移动右节点
		$sql = $this->_db->quoteInto(
			'UPDATE '.$this->_table.' SET '.$this->_right.' = '.$this->_right.' + 2 WHERE '.$this->_right. ' > ?',
			$right_node - 1
		);
		$this->_db->query($sql);
		
		// 插入新的树节点
		unset($data['id']);
		$data[$this->_left] = $right_node;
		$data[$this->_right] = $right_node + 1;
		
		return $this->_db->insert($this->_table, $data);
	}
	
	
	/**
	 * 删除树
	 * 
	 * @param integer 当前节点
	 * @param bool 是否是移除，默认删除。
	 * @return bool
	 */
	public function deleteTree($id)
	{
		$select = new Zend_Db_Select($this->_db);
		$select->from($this->_table)
			->where($this->_pk.' =?', $id);
		
		$data = $this->_db->fetchRow($select);
		
		if (empty($data))
		{
			return trigger_error('The node is not exists or already removed', E_USER_WARNING);
		}
		
		if ($data[$this->_left] == 1 || $data[$this->_left] == 0)
		{
			return trigger_error('Can not delete the root node', E_USER_WARNING);
		}
		
		// 禁止删除含有子分类的类
		if (0 != ($data[$this->_right] - $data[$this->_left] - 1) / 2)
		{
			return trigger_error('Child node contains', E_USER_WARNING);
		}
		
		// 删除节点
		$where = $this->_db->quoteInto($this->_pk .'= ?', $id);
		if($this->_db->delete($this->_table, $where))
		{
			// 移动树-左
			$sql = $this->_db->quoteInto(
				'UPDATE '.$this->_table.' SET '.$this->_left.' = '.$this->_left.' - 2 WHERE '.$this->_left. ' > ?',
				$data[$this->_left]
			);
			$this->_db->query($sql);
			
			// 移动树-右
			$sql = $this->_db->quoteInto(
				'UPDATE '.$this->_table.' SET '.$this->_right.' = '.$this->_right.' - 2 WHERE '.$this->_right. ' > ?',
				$data[$this->_left]
			);
			$this->_db->query($sql);
			
			return true;
		}
		
		return false;
		
	}
	
	/**
	 * 获取当节点的直属父级节点信息
	 *
	 * 通过节点id获取直属上级节点数组
	 *
	 * @return array()
	 */
	public function getParentNode($id)
	{
		$treePath = $this->getTreePath($id);
	
		//指定节点不存在或已被removed
		if($treePath == false)
			return trigger_error('The node is not exists or already removed');
	
			
		//当前节点已是根节点
		if($this->isRoot($id))
		{
			return trigger_error('The node is root node');
		}else{
			$index = count($treePath)-2;
			return $treePath[$index];
		}
	}
	
	/**
	 * 获取树路径
	 *
	 * 基于node对象
	 *
	 * @return array()
	 */
	public function getTreePath($id)
	{
		$node = $this->row($id);
	
		if (empty($node))
			return trigger_error('The node is not exists or already removed');
	
		$select = new Zend_Db_Select($this->_db);
		$select->from($this->_table);
		$select->where($this->_left . '< ?', $node[$this->_left] + 1);
		$select->where($this->_right . '> ?', $node[$this->_right]  - 1);
		$select->order($this->_left . ' ASC');
		
		return $this->_db->fetchAll($select);
	}
	
	/**
	 * 获取子节点ID
	 *
	 * 基于node对象
	 *
	 * @return array()
	 */
	public function getLeafId($id)
	{
		$node = $this->row($id);
	
		if (empty($node))
			return trigger_error('The node is not exists or already removed');

		
		$select = new Zend_Db_Select($this->_db);
		$select->from($this->_table, array($this->_pk));
		$select->where($this->_left . '> ?', $node[$this->_left]);
		$select->where($this->_right. '< ?', $node[$this->_right]);
		
		$rows = $this->_db->fetchAll($select);
	
		if (empty($rows))
		{
			return array();
		}
	
		$ID = array();
	
		foreach ( $rows as $r )
		{
			$ID[] = $r[$this->_pk];
		}
	
		return $ID;
	}
	
	/**
	 * 读取子节点数量
	 *
	 * 基于node对象
	 *
	 * @return array()
	 */
	public function countLeaf($id)
	{
		$node = $this->row($id);
	
		if (empty($node))
			return trigger_error('The node is not exists or already removed');
	
		return (($node[$this->_right] - $node[$this->_left] - 1) / 2);
	}
	
	/**
	 * 是否为根节点
	 *
	 * 基于node对象
	 *
	 * @return array()
	 */
	public function isRoot($id)
	{
		$node = $this->row($id);
	
		if (empty($node))
			return trigger_error('The node is not exists or already removed');
		
		return (($node[$this->_right] - $node[$this->_left] - 1) / 2) ? true : false;
	}
}